home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’96 / VideoFolder 1.0a / Source / MoreFiles 1.4.1 / MoreDesktopMgr.c < prev    next >
Text File  |  1995-12-21  |  31KB  |  1,153 lines

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    A collection of useful high-level Desktop Manager routines.
  5. **    If the Desktop Manager isn't available, use the Desktop file
  6. **    for 'read' operations.
  7. **
  8. **    We do more because we can...
  9. **
  10. **    by Jim Luther and Nitin Ganatra, Apple Developer Technical Support Emeriti
  11. **
  12. **    File:    MoreDesktopMgr.c
  13. **
  14. **    Copyright © 1992-1995 Apple Computer, Inc.
  15. **    All rights reserved.
  16. **
  17. **    You may incorporate this sample code into your applications without
  18. **    restriction, though the sample code has been provided "AS IS" and the
  19. **    responsibility for its operation is 100% yours.  However, what you are
  20. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  21. **    after having made changes. If you're going to re-distribute the source,
  22. **    we require that you make it clear in the source that the code was
  23. **    descended from Apple Sample Code, but that you've made changes.
  24. */
  25.  
  26. #include <Types.h>
  27. #include <Errors.h>
  28. #include <Memory.h>
  29. #include <Files.h>
  30. #include <Resources.h>
  31. #include <Icons.h>
  32. #include "MoreFiles.h"
  33. #include "MoreFilesExtras.h"
  34. #include "Search.h"
  35. #include "MoreDesktopMgr.h"
  36.  
  37. /*****************************************************************************/
  38.  
  39. /*    Desktop file notes:
  40. **
  41. **    •    The Desktop file is owned by the Finder and is normally open by the
  42. **        Finder. That means that we only have read-only access to the Desktop
  43. **        file.
  44. **    •    Since the Resource Manager doesn't support shared access to resource
  45. **        files and we're using read-only access, we don't ever leave the
  46. **        Desktop file open.  We open a path to it, get the data we want out
  47. **        of it, and then close the open path. This is the only safe way to
  48. **        open a resource file with read-only access since some other program
  49. **        could have it open with write access.
  50. **    •    The bundle related resources in the Desktop file are normally
  51. **        purgable, so when we're looking through them, we don't bother to
  52. **        release resources we're done looking at - closing the resource file
  53. **        (which we always do) will release them.
  54. **    •    Since we can't assume the Desktop file is named "Desktop"
  55. **        (it probably is everywhere but France), we get the Desktop
  56. **        file's name by searching the volume's root directory for a file
  57. **        with fileType == 'FNDR' and creator == 'ERIK'. The only problem with
  58. **        this scheme is that someone could create another file with that type
  59. **        and creator in the root directory and we'd find the wrong file.
  60. **        The chances of this are very slim.
  61. */
  62.  
  63. /*****************************************************************************/
  64.  
  65. /* local defines */
  66.  
  67. enum
  68. {
  69.     kBNDLResType    = 'BNDL',
  70.     kFREFResType    = 'FREF',
  71.     kIconFamResType    = 'ICN#',
  72.     kFCMTResType    = 'FCMT',
  73.     kAPPLResType    = 'APPL'
  74. };
  75.  
  76. /*****************************************************************************/
  77.  
  78. /* local data structures */
  79.  
  80. #if PRAGMA_ALIGN_SUPPORTED
  81. #pragma options align=mac68k
  82. #endif
  83.  
  84. struct IDRec
  85. {
  86.     short        localID;
  87.     short        rsrcID;
  88. };
  89. typedef struct IDRec IDRec;
  90. typedef    IDRec *IDRecPtr;
  91.  
  92. struct BundleType
  93. {
  94.     OSType        type;            /* 'ICN#' or 'FREF' */
  95.     short        count;            /* number of IDRecs - 1 */
  96.     IDRec        idArray[1];
  97. };
  98. typedef struct BundleType BundleType;
  99. typedef BundleType *BundleTypePtr;
  100.  
  101. struct BNDLRec
  102. {
  103.     OSType        signature;        /* creator type signature */
  104.     short        versionID;        /* version - should always be 0 */
  105.     short        numTypes;        /* number of elements in typeArray - 1 */
  106.     BundleType    typeArray[1];
  107. };
  108. typedef struct BNDLRec BNDLRec;
  109. typedef BNDLRec **BNDLRecHandle;
  110.  
  111. struct FREFRec
  112. {
  113.     OSType        fileType;        /* file type */
  114.     short        iconID;            /* icon local ID */
  115.     Str255        fileName;        /* file name */
  116. };
  117. typedef struct FREFRec FREFRec;
  118. typedef FREFRec **FREFRecHandle;
  119.  
  120. struct APPLRec
  121. {
  122.     OSType        creator;        /* creator type signature */
  123.     long        parID;            /* parent directory ID */
  124.     Str255        applName;        /* application name */
  125. };
  126. typedef struct APPLRec APPLRec;
  127. typedef APPLRec *APPLRecPtr;
  128.  
  129. #if PRAGMA_ALIGN_SUPPORTED
  130. #pragma options align=reset
  131. #endif
  132.  
  133. /*****************************************************************************/
  134.  
  135. /* static prototypes */
  136.  
  137. static    OSErr    GetDesktopFileName(short vRefNum,
  138.                                    Str255 desktopName);
  139.  
  140. static    OSErr    GetAPPLFromDesktopFile(StringPtr volName,
  141.                                        short vRefNum,
  142.                                        OSType creator,
  143.                                        short *applVRefNum,
  144.                                        long *applParID,
  145.                                        Str255 applName);
  146.  
  147. static    OSErr    FindBundleGivenCreator(OSType creator,
  148.                                        BNDLRecHandle *returnBndl);
  149.                                        
  150. static    OSErr    FindTypeInBundle(OSType typeToFind,
  151.                                  BNDLRecHandle theBndl,
  152.                                  BundleTypePtr *returnBundleType);
  153.                                          
  154. static    OSErr    GetLocalIDFromFREF(BundleTypePtr theBundleType,
  155.                                    OSType fileType,
  156.                                    short *iconLocalID);
  157.  
  158. static    OSErr    GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
  159.                                          short iconLocalID,
  160.                                          short *iconRsrcID);
  161.  
  162. static    OSType    DTIconToResIcon(short iconType);
  163.  
  164. static    OSErr    GetIconFromDesktopFile(StringPtr volName,
  165.                                        short vRefNum,
  166.                                        short iconType,
  167.                                        OSType fileCreator,
  168.                                        OSType fileType,
  169.                                        Handle *iconHandle);
  170.  
  171. static    OSErr    GetCommentID(short vRefNum,
  172.                              long dirID,
  173.                              StringPtr name,
  174.                              short *commentID);
  175.  
  176. static    OSErr    GetCommentFromDesktopFile(short vRefNum,
  177.                                           long dirID,
  178.                                           StringPtr name,
  179.                                           Str255 comment);
  180.  
  181. /*****************************************************************************/
  182.  
  183. /*
  184. **    GetDesktopFileName
  185. **
  186. **    Get the name of the Desktop file.
  187. */
  188. static    OSErr    GetDesktopFileName(short vRefNum,
  189.                                    Str255 desktopName)
  190. {
  191.     OSErr            error;
  192.     HParamBlockRec    pb;
  193.     short            index;
  194.     Boolean            found = false;
  195.     
  196.     pb.fileParam.ioNamePtr = desktopName;
  197.     pb.fileParam.ioVRefNum = vRefNum;
  198.     pb.fileParam.ioFVersNum = 0;
  199.     index = 1;
  200.     do
  201.     {
  202.         pb.fileParam.ioDirID = fsRtDirID;
  203.         pb.fileParam.ioFDirIndex = index;
  204.         error = PBHGetFInfoSync(&pb);
  205.         if ( error == noErr )
  206.         {
  207.             if ( (pb.fileParam.ioFlFndrInfo.fdType == 'FNDR') &&
  208.                  (pb.fileParam.ioFlFndrInfo.fdCreator == 'ERIK') )
  209.             {
  210.                 found = true;
  211.             }
  212.         }
  213.         ++index;
  214.     } while ( (error == noErr) && !found );
  215.     
  216.     return ( error );
  217. }
  218.  
  219. /*****************************************************************************/
  220.  
  221. pascal    OSErr    DTOpen(StringPtr volName,
  222.                        short vRefNum,
  223.                        short *dtRefNum,
  224.                        Boolean *newDTDatabase)
  225. {
  226.     OSErr error;
  227.     GetVolParmsInfoBuffer volParmsInfo;
  228.     long infoSize;
  229.     DTPBRec pb;
  230.     
  231.     /* Check for volume Desktop Manager support before calling */
  232.     infoSize = sizeof(GetVolParmsInfoBuffer);
  233.     error = HGetVolParms(volName, vRefNum, &volParmsInfo, &infoSize);
  234.     if ( error == noErr )
  235.     {
  236.         if ( hasDesktopMgr(volParmsInfo) )
  237.         {
  238.             pb.ioNamePtr = volName;
  239.             pb.ioVRefNum = vRefNum;
  240.             error = PBDTOpenInform(&pb);
  241.             /* PBDTOpenInform informs us if the desktop was just created */
  242.             /* by leaving the low bit of ioTagInfo clear (0) */
  243.             *newDTDatabase = ((pb.ioTagInfo & 1L) == 0);
  244.             if ( error == paramErr )
  245.             {
  246.                 error = PBDTGetPath(&pb);
  247.                 /* PBDTGetPath doesn't tell us if the database is new */
  248.                 /* so assume it is not new */
  249.                 *newDTDatabase = false;
  250.             }
  251.             *dtRefNum = pb.ioDTRefNum;
  252.         }
  253.         else
  254.             error = paramErr;
  255.     }
  256.     return ( error );
  257. }
  258.  
  259. /*****************************************************************************/
  260.  
  261. /*
  262. **    GetAPPLFromDesktopFile
  263. **
  264. **    Get a application's location from the
  265. **    Desktop file's 'APPL' resources.
  266. */
  267. static    OSErr    GetAPPLFromDesktopFile(StringPtr volName,
  268.                                        short vRefNum,
  269.                                        OSType creator,
  270.                                        short *applVRefNum,
  271.                                        long *applParID,
  272.                                        Str255 applName)
  273. {
  274.     OSErr error;
  275.     short realVRefNum;
  276.     Str255 desktopName;
  277.     short savedResFile;
  278.     short dfRefNum;
  279.     Handle applResHandle;
  280.     Boolean foundCreator;
  281.     Ptr applPtr;
  282.     long applSize;
  283.     
  284.     error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
  285.     if ( error == noErr )
  286.     {
  287.         error = GetDesktopFileName(realVRefNum, desktopName);
  288.         if ( error == noErr )
  289.         {
  290.             savedResFile = CurResFile();
  291.             /*
  292.             **    Open the 'Desktop' file in the root directory. (because
  293.             **    opening the resource file could preload unwanted resources,
  294.             **    bracket the call with SetResLoad(s))
  295.             */
  296.             SetResLoad(false);
  297.             dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
  298.             SetResLoad(true);
  299.             
  300.             if ( dfRefNum != -1)
  301.             {
  302.                 /* Get 'APPL' resource ID 0 */
  303.                 applResHandle = Get1Resource(kAPPLResType, 0);
  304.                 if ( applResHandle != NULL )
  305.                 {
  306.                     applSize = GetHandleSize((Handle)applResHandle);
  307.                     if ( applSize != 0 )    /* make sure the APPL resource isn't empty */
  308.                     {
  309.                         foundCreator = false;
  310.                         applPtr = *applResHandle;
  311.                         
  312.                         /* APPL's don't have a count so I have to use the size as the bounds */
  313.                         while ( (foundCreator == false) &&
  314.                                 (applPtr < (*applResHandle + applSize)) )
  315.                         {
  316.                             if ( ((APPLRecPtr)applPtr)->creator == creator )
  317.                             {
  318.                                 foundCreator = true;
  319.                             }
  320.                             else
  321.                             {
  322.                                 /* fun with pointer math... */
  323.                                 applPtr += sizeof(OSType) +
  324.                                            sizeof(long) +
  325.                                            ((APPLRecPtr)applPtr)->applName[0] + 1;
  326.                                 /* application mappings are word aligned within the resource */
  327.                                 if ( ((unsigned long)applPtr % 2) != 0 )
  328.                                     applPtr += 1;
  329.                             }
  330.                         }
  331.                         if ( foundCreator == true )
  332.                         {
  333.                             *applVRefNum = realVRefNum;
  334.                             *applParID = ((APPLRecPtr)applPtr)->parID;
  335.                             BlockMoveData(((APPLRecPtr)applPtr)->applName,
  336.                                           applName,
  337.                                           ((APPLRecPtr)applPtr)->applName[0] + 1);
  338.                             error = noErr;
  339.                         }
  340.                     }
  341.                     else
  342.                         error = afpItemNotFound;    /* no APPL mapping available */
  343.                 }
  344.                 else
  345.                     error = afpItemNotFound;    /* no APPL mapping available */
  346.                 
  347.                 /* restore the resource chain and close the Desktop file */
  348.                 UseResFile(savedResFile);
  349.                 CloseResFile(dfRefNum);
  350.             }
  351.             else
  352.                 error = afpItemNotFound;
  353.         }
  354.     }
  355.     return ( error );
  356. }
  357.  
  358. /*****************************************************************************/
  359.  
  360. pascal    OSErr    DTGetAPPL(StringPtr volName,
  361.                           short vRefNum,
  362.                           OSType creator,
  363.                           short *applVRefNum,
  364.                           long *applParID,
  365.                           Str255 applName)
  366. {
  367.     OSErr error;
  368.     UniversalFMPB pb;
  369.     short dtRefNum;
  370.     Boolean newDTDatabase;
  371.     short realVRefNum;
  372.     short index;
  373.     Boolean applFound;
  374.     FSSpec spec;
  375.     long actMatchCount;
  376.     
  377.     /* get the real vRefNum */
  378.     error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
  379.     if ( error == noErr )
  380.     {
  381.         error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
  382.         if ( error == noErr )
  383.         {
  384.             if ( !newDTDatabase )
  385.             {
  386.                 index = 0;
  387.                 applFound = false;
  388.                 do
  389.                 {
  390.                     pb.dtPB.ioNamePtr = applName;
  391.                     pb.dtPB.ioDTRefNum = dtRefNum;
  392.                     pb.dtPB.ioIndex = index;
  393.                     pb.dtPB.ioFileCreator = creator;
  394.                     error = PBDTGetAPPLSync(&pb.dtPB);
  395.                     if ( error == noErr )
  396.                     {
  397.                         /* got a match - see if it is valid */
  398.                         
  399.                         *applVRefNum = realVRefNum; /* get the vRefNum now */
  400.                         *applParID = pb.dtPB.ioAPPLParID; /* get the parent ID now */
  401.     
  402.                         /* pb.hPB.fileParam.ioNamePtr is already set */
  403.                         pb.hPB.fileParam.ioVRefNum = realVRefNum;
  404.                         pb.hPB.fileParam.ioFVersNum = 0;
  405.                         pb.hPB.fileParam.ioDirID = *applParID;
  406.                         pb.hPB.fileParam.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
  407.                         if ( PBHGetFInfoSync(&pb.hPB) == noErr )
  408.                         {
  409.                             if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator == creator) &&
  410.                                  (pb.hPB.fileParam.ioFlFndrInfo.fdType == 'APPL') )
  411.                             {
  412.                                 applFound = true;
  413.                             }
  414.                         }
  415.                     }
  416.                     ++index;
  417.                 } while ( (error == noErr) && !applFound );
  418.                 if ( error == fnfErr )
  419.                     error = afpItemNotFound;
  420.             }
  421.             else
  422.                 /* Desktop database is empty (new), set error to try CatSearch */
  423.                 error = afpItemNotFound;
  424.         }
  425.         /* acceptable errors from Desktop Manager to continue are paramErr or afpItemNotFound */
  426.         if ( error == paramErr )
  427.         {
  428.             /* if paramErr, the volume didn't support the Desktop Manager */
  429.             /* try the Desktop file */
  430.             
  431.             error = GetAPPLFromDesktopFile(volName, vRefNum, creator,
  432.                                             applVRefNum, applParID, applName);
  433.             if ( error == noErr )
  434.             {
  435.                 /* got a match - see if it is valid */
  436.                 
  437.                 pb.hPB.fileParam.ioNamePtr = applName;
  438.                 pb.hPB.fileParam.ioVRefNum = *applVRefNum;
  439.                 pb.hPB.fileParam.ioFVersNum = 0;
  440.                 pb.hPB.fileParam.ioDirID = *applParID;
  441.                 pb.hPB.fileParam.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
  442.                 if ( PBHGetFInfoSync(&pb.hPB) == noErr )
  443.                 {
  444.                     if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator != creator) ||
  445.                          (pb.hPB.fileParam.ioFlFndrInfo.fdType != 'APPL') )
  446.                     {
  447.                         error = afpItemNotFound;
  448.                     }
  449.                 }
  450.                 else if ( error == fnfErr )
  451.                     error = afpItemNotFound;
  452.             }
  453.         }
  454.         /* acceptable error from DesktopFile code to continue is afpItemNotFound */
  455.         if ( error == afpItemNotFound )
  456.         {
  457.             /* Couldn't be found in the Desktop file either, try searching with CatSearch */
  458.             
  459.             error = CreatorTypeFileSearch(NULL, realVRefNum, creator, kAPPLResType, &spec, 1,
  460.                                             &actMatchCount, true);
  461.             if ( (error == noErr) || (error == eofErr) )
  462.             {
  463.                 if ( actMatchCount > 0 )
  464.                 {
  465.                     *applVRefNum = spec.vRefNum;
  466.                     *applParID = spec.parID;
  467.                     BlockMoveData(spec.name, applName, spec.name[0] + 1);
  468.                 }
  469.                 else
  470.                     error = afpItemNotFound;
  471.             }
  472.         }
  473.     }
  474.     return ( error );
  475. }
  476.  
  477. /*****************************************************************************/
  478.  
  479. pascal    OSErr    FSpDTGetAPPL(StringPtr volName,
  480.                              short vRefNum,
  481.                              OSType creator,
  482.                              FSSpec *spec)
  483. {
  484.     return ( DTGetAPPL(volName, vRefNum, creator,
  485.                         &(spec->vRefNum), &(spec->parID), spec->name) );
  486. }
  487.  
  488. /*****************************************************************************/
  489.  
  490. /*
  491. **    FindBundleGivenCreator
  492. **
  493. **    Search the current resource file for the 'BNDL' resource with the given
  494. **    creator and return a handle to it.
  495. */
  496. static    OSErr    FindBundleGivenCreator(OSType creator,
  497.                                        BNDLRecHandle *returnBndl)
  498. {
  499.     OSErr            error;
  500.     short            numOfBundles;
  501.     short            index;
  502.     BNDLRecHandle    theBndl;
  503.     
  504.     error = afpItemNotFound;    /* default to not found */
  505.     
  506.     /* Search each BNDL resource until we find the one with a matching creator. */
  507.     
  508.     numOfBundles = Count1Resources(kBNDLResType);
  509.     index = 1;
  510.     *returnBndl = NULL;
  511.     
  512.     while ( (index <= numOfBundles) && (*returnBndl == NULL) )
  513.     {
  514.         theBndl = (BNDLRecHandle)Get1IndResource(kBNDLResType, index);
  515.         
  516.         if ( theBndl != NULL )
  517.         {
  518.             if ( (*theBndl)->signature == creator )
  519.             {
  520.                 /* numTypes and typeArray->count will always be the actual count minus 1, */
  521.                 /* so 0 in both fields is valid. */
  522.                 if ( ((*theBndl)->numTypes >= 0) && ((*theBndl)->typeArray->count >= 0) )
  523.                 {
  524.                     /* got it */
  525.                     *returnBndl = theBndl;
  526.                     error = noErr;
  527.                 }
  528.             }
  529.         }    
  530.         
  531.         index ++;
  532.     }
  533.     
  534.     return ( error );
  535. }
  536.  
  537. /*****************************************************************************/
  538.  
  539. /*
  540. **    FindTypeInBundle
  541. **
  542. **    Given a Handle to a BNDL return a pointer to the desired type
  543. **    in it. If the type is not found, or if the type's count < 0,
  544. **    return afpItemNotFound.
  545. */
  546. static    OSErr    FindTypeInBundle(OSType typeToFind,
  547.                                  BNDLRecHandle theBndl,
  548.                                  BundleTypePtr *returnBundleType)
  549. {
  550.     OSErr            error;
  551.     short            index;
  552.     Ptr                ptrIterator;    /* use a Ptr so we can do ugly pointer math */
  553.     
  554.     error = afpItemNotFound;    /* default to not found */
  555.     
  556.     ptrIterator = (Ptr)((*theBndl)->typeArray);
  557.     index = 0;
  558.     *returnBundleType = NULL;
  559.  
  560.     while ( (index < ((*theBndl)->numTypes + 1)) &&
  561.             (*returnBundleType == NULL) )
  562.     {
  563.         if ( (((BundleTypePtr)ptrIterator)->type == typeToFind) &&
  564.              (((BundleTypePtr)ptrIterator)->count >= 0) )
  565.         {
  566.                 *returnBundleType = (BundleTypePtr)ptrIterator;
  567.                 error = noErr;
  568.         }
  569.         else
  570.         {
  571.             ptrIterator += ( sizeof(OSType) +
  572.                              sizeof(short) +
  573.                              ( sizeof(IDRec) * (((BundleTypePtr)ptrIterator)->count + 1) ) );
  574.             ++index;
  575.         }
  576.     }
  577.         
  578.     return ( error );
  579. }
  580.  
  581. /*****************************************************************************/
  582.  
  583. /*
  584. **    GetLocalIDFromFREF
  585. **
  586. **    Given a pointer to a 'FREF' BundleType record, load each 'FREF' resource
  587. **    looking for a matching fileType. If a matching fileType is found, return
  588. **    its icon local ID. If no match is found, return afpItemNotFound as the
  589. **    function result.
  590. */
  591. static    OSErr    GetLocalIDFromFREF(BundleTypePtr theBundleType,
  592.                                    OSType fileType,
  593.                                    short *iconLocalID)
  594. {
  595.     OSErr            error;
  596.     short            index;
  597.     IDRecPtr        idIterator;
  598.     FREFRecHandle    theFref;
  599.     
  600.     error = afpItemNotFound;    /* default to not found */
  601.     
  602.     /* For each localID in this type, get the FREF resource looking for fileType */
  603.     index = 0;
  604.     idIterator = &theBundleType->idArray[0];
  605.     *iconLocalID = 0;
  606.     
  607.     while ( (index <= (theBundleType->count + 1)) && (*iconLocalID == 0) )
  608.     {
  609.         theFref = (FREFRecHandle)Get1Resource(kFREFResType, idIterator->rsrcID);
  610.         if ( theFref != NULL )
  611.         {
  612.             if ( (*theFref)->fileType == fileType )
  613.             {
  614.                 *iconLocalID = (*theFref)->iconID;
  615.                 error = noErr;
  616.             }
  617.         }
  618.         
  619.         ++idIterator;
  620.         ++index;
  621.     }
  622.     
  623.     return ( error );
  624. }
  625.  
  626. /*****************************************************************************/
  627.  
  628. /*
  629. **    GetIconRsrcIDFromLocalID
  630. **
  631. **    Given a pointer to a 'ICN#' BundleType record, look for the IDRec with
  632. **    the localID that matches iconLocalID. If a matching IDRec is found,
  633. **    return the IDRec's rsrcID field value. If no match is found, return
  634. **    afpItemNotFound as the function result.
  635. */
  636. static    OSErr    GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
  637.                                          short iconLocalID,
  638.                                          short *iconRsrcID)
  639. {
  640.     OSErr        error;
  641.     short        index;
  642.     IDRecPtr    idIterator;
  643.     
  644.     error = afpItemNotFound;    /* default to not found */
  645.     
  646.     /* Find the rsrcID of the icon family type, given the localID */
  647.     index = 0;
  648.     idIterator = &theBundleType->idArray[0];
  649.     *iconRsrcID = 0;
  650.     
  651.     while ( (index <= (theBundleType->count+1)) && (*iconRsrcID == 0) )
  652.     {
  653.         if ( idIterator->localID == iconLocalID )
  654.         {
  655.             *iconRsrcID = idIterator->rsrcID;
  656.             error = noErr;
  657.         }
  658.         
  659.         idIterator ++;
  660.         index ++;
  661.     }
  662.     
  663.     return ( error );
  664. }
  665.  
  666. /*****************************************************************************/
  667.  
  668. /*
  669. **    DTIconToResIcon
  670. **
  671. **    Map a Desktop Manager icon type to the corresponding resource type.
  672. **    Return (OSType)0 if there is no corresponding resource type.
  673. */
  674. static    OSType    DTIconToResIcon(short iconType)
  675. {
  676.     OSType    resType;
  677.     
  678.     switch ( iconType )
  679.     {
  680.         case kLargeIcon:
  681.             resType = large1BitMask;
  682.             break;
  683.         case kLarge4BitIcon:
  684.             resType = large4BitData;
  685.             break;
  686.         case kLarge8BitIcon:
  687.             resType = large8BitData;
  688.             break;
  689.         case kSmallIcon:
  690.             resType = small1BitMask;
  691.             break;
  692.         case kSmall4BitIcon:
  693.             resType = small4BitData;
  694.             break;
  695.         case kSmall8BitIcon:
  696.             resType = small8BitData;
  697.             break;
  698.         default:
  699.             resType = (OSType)0;
  700.             break;
  701.     }
  702.     
  703.     return ( resType );
  704. }
  705.  
  706. /*****************************************************************************/
  707.  
  708. /*
  709. **    GetIconFromDesktopFile
  710. **
  711. **    INPUT a pointer to a non-existent Handle, because we'll allocate one
  712. **
  713. **    search each BNDL resource for the right fileCreator and once we get it
  714. **        find the 'FREF' type in BNDL
  715. **        for each localID in the type, open the FREF resource
  716. **            if the FREF is the desired fileType
  717. **                get its icon localID
  718. **                get the ICN# type in BNDL
  719. **                get the icon resource number from the icon localID
  720. **                get the icon resource type from the desktop mgr's iconType
  721. **                get the icon of that type and number
  722. */
  723. static    OSErr    GetIconFromDesktopFile(StringPtr volName,
  724.                                        short vRefNum,
  725.                                        short iconType,
  726.                                        OSType fileCreator,
  727.                                        OSType fileType,
  728.                                        Handle *iconHandle)
  729. {
  730.     OSErr            error;
  731.     short            realVRefNum;
  732.     Str255            desktopName;
  733.     short            savedResFile;
  734.     short            dfRefNum;
  735.     BNDLRecHandle    theBndl = NULL;
  736.     BundleTypePtr    theBundleType;
  737.     short            iconLocalID;
  738.     short            iconRsrcID;
  739.     OSType            iconRsrcType;
  740.     Handle            returnIconHandle;    
  741.     char            bndlState;
  742.     
  743.     *iconHandle = NULL;
  744.     
  745.     error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
  746.     if ( error == noErr )
  747.     {
  748.         error = GetDesktopFileName(realVRefNum, desktopName);
  749.         if ( error == noErr )
  750.         {
  751.             savedResFile = CurResFile();
  752.         
  753.             /*
  754.             **    Open the 'Desktop' file in the root directory. (because
  755.             **    opening the resource file could preload unwanted resources,
  756.             **    bracket the call with SetResLoad(s))
  757.             */
  758.             SetResLoad(false);
  759.             dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
  760.             SetResLoad(true);
  761.         
  762.             if ( dfRefNum != -1 )
  763.             {
  764.                 /*
  765.                 **    Find the BNDL resource with the specified creator.
  766.                 */
  767.                 error = FindBundleGivenCreator(fileCreator, &theBndl);
  768.                 if ( error == noErr )
  769.                 {
  770.                     /* Lock the BNDL resource so it won't be purged when other resources are loaded */
  771.                     bndlState = HGetState((Handle)theBndl);
  772.                     HLock((Handle)theBndl);
  773.                     
  774.                     /* Find the 'FREF' BundleType record in the BNDL resource. */
  775.                     error = FindTypeInBundle(kFREFResType, theBndl, &theBundleType);
  776.                     if ( error == noErr )
  777.                     {
  778.                         /* Find the local ID in the 'FREF' resource with the specified fileType */
  779.                         error = GetLocalIDFromFREF(theBundleType, fileType, &iconLocalID);
  780.                         if ( error == noErr )
  781.                         {
  782.                             /* Find the 'ICN#' BundleType record in the BNDL resource. */
  783.                             error = FindTypeInBundle(kIconFamResType, theBndl, &theBundleType);
  784.                             if ( error == noErr )
  785.                             {
  786.                                 /* Find the icon's resource ID in the 'ICN#' BundleType record */
  787.                                 error = GetIconRsrcIDFromLocalID(theBundleType, iconLocalID, &iconRsrcID);
  788.                                 if ( error == noErr )
  789.                                 {
  790.                                     /* Map Desktop Manager icon type to resource type */
  791.                                     iconRsrcType = DTIconToResIcon(iconType);
  792.                                     
  793.                                     if ( iconRsrcType != (OSType)0 )
  794.                                     {
  795.                                         /* Load the icon */
  796.                                         returnIconHandle = Get1Resource(iconRsrcType, iconRsrcID);
  797.                                         if ( returnIconHandle != NULL )
  798.                                         {
  799.                                             /* Copy the resource handle, and return the copy */
  800.                                             HandToHand(&returnIconHandle);
  801.                                             if ( MemError() == noErr )
  802.                                                 *iconHandle = returnIconHandle;
  803.                                             else
  804.                                                 error = afpItemNotFound;
  805.                                         }
  806.                                         else
  807.                                             error = afpItemNotFound;
  808.                                     }
  809.                                 }
  810.                             }
  811.                         }
  812.                     }
  813.                     /* Restore the state of the BNDL resource */ 
  814.                     HSetState((Handle)theBndl, bndlState);
  815.                 }
  816.                 /* Restore the resource chain and close the Desktop file */
  817.                 UseResFile(savedResFile);
  818.                 CloseResFile(dfRefNum);
  819.             }
  820.             else
  821.                 error = ResError(); /* could not open Desktop file */
  822.         }
  823.     }
  824.     
  825.     return ( error );
  826. }
  827.  
  828. /*****************************************************************************/
  829.  
  830. pascal    OSErr    DTGetIcon(StringPtr volName,
  831.                           short vRefNum,
  832.                           short iconType,
  833.                           OSType fileCreator,
  834.                           OSType fileType,
  835.                           Handle *iconHandle)
  836. {
  837.     OSErr error;
  838.     DTPBRec pb;
  839.     short dtRefNum;
  840.     Boolean newDTDatabase;
  841.     Size bufferSize;
  842.     
  843.     *iconHandle = NULL;
  844.     error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
  845.     if ( error == noErr )
  846.     {
  847.         /* there was a desktop database and it's now open */
  848.         
  849.         if ( !newDTDatabase )    /* don't bother to look in a new (empty) database */
  850.         {
  851.             /* get the buffer size for the requested icon type */
  852.             switch ( iconType )
  853.             {
  854.                 case kLargeIcon:
  855.                     bufferSize = kLargeIconSize;
  856.                     break;
  857.                 case kLarge4BitIcon:
  858.                     bufferSize = kLarge4BitIconSize;
  859.                     break;
  860.                 case kLarge8BitIcon:
  861.                     bufferSize = kLarge8BitIconSize;
  862.                     break;
  863.                 case kSmallIcon:
  864.                     bufferSize = kSmallIconSize;
  865.                     break;
  866.                 case kSmall4BitIcon:
  867.                     bufferSize = kSmall4BitIconSize;
  868.                     break;
  869.                 case kSmall8BitIcon:
  870.                     bufferSize = kSmall8BitIconSize;
  871.                     break;
  872.                 default:
  873.                     iconType = 0;
  874.                     bufferSize = 0;
  875.                     break;
  876.             }
  877.             if ( bufferSize != 0 )
  878.             {
  879.                 *iconHandle = NewHandle(bufferSize);
  880.                 if ( *iconHandle != NULL )
  881.                 {
  882.                     HLock(*iconHandle);
  883.         
  884.                     pb.ioDTRefNum = dtRefNum;
  885.                     pb.ioTagInfo = 0;
  886.                     pb.ioDTBuffer = **iconHandle;
  887.                     pb.ioDTReqCount = bufferSize;
  888.                     pb.ioIconType = iconType;
  889.                     pb.ioFileCreator = fileCreator;
  890.                     pb.ioFileType = fileType;
  891.                     error = PBDTGetIconSync(&pb);
  892.     
  893.                     HUnlock(*iconHandle);
  894.                     
  895.                     if ( error != noErr )
  896.                     {
  897.                         DisposeHandle(*iconHandle);    /* dispose of the allocated memory */
  898.                         *iconHandle = NULL;
  899.                     }
  900.                 }
  901.                 else
  902.                     error = memFullErr;    /* handle could not be allocated */
  903.             }
  904.             else
  905.                 error = paramErr;    /* unknown icon type requested */
  906.         }
  907.         else
  908.             error = afpItemNotFound;    /* the desktop database was empty - nothing to return */
  909.     }
  910.     else
  911.     {
  912.         /* There is no desktop database - try the Desktop file */
  913.         
  914.         error = GetIconFromDesktopFile(volName, vRefNum, iconType,
  915.                                         fileCreator, fileType, iconHandle);
  916.     }
  917.     
  918.     return ( error );
  919. }
  920.  
  921. /*****************************************************************************/
  922.  
  923. pascal    OSErr    DTSetComment(short vRefNum,
  924.                              long dirID,
  925.                              StringPtr name,
  926.                              ConstStr255Param comment)
  927. {
  928.     DTPBRec pb;
  929.     OSErr error;
  930.     short dtRefNum;
  931.     Boolean newDTDatabase;
  932.  
  933.     error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
  934.     if ( error == noErr )
  935.     {
  936.         pb.ioDTRefNum = dtRefNum;
  937.         pb.ioNamePtr = name;
  938.         pb.ioDirID = dirID;
  939.         pb.ioDTBuffer = (Ptr)&comment[1];
  940.         /* Truncate the comment to 200 characters just in case */
  941.         /* some file system doesn't range check */
  942.         if ( comment[0] <= 200 )
  943.             pb.ioDTReqCount = comment[0];
  944.         else
  945.             pb.ioDTReqCount = 200;
  946.         error = PBDTSetCommentSync(&pb);
  947.     }
  948.     return (error);
  949. }
  950.  
  951. /*****************************************************************************/
  952.  
  953. pascal    OSErr    FSpDTSetComment(const FSSpec *spec,
  954.                               ConstStr255Param comment)
  955. {
  956.     return (DTSetComment(spec->vRefNum, spec->parID, (StringPtr)spec->name, comment));
  957. }
  958.  
  959. /*****************************************************************************/
  960.  
  961. /*
  962. **    GetCommentID
  963. **
  964. **    Get the comment ID number for the Desktop file's 'FCMT' resource ID from
  965. **    the file or folders fdComment (frComment) field.
  966. */
  967. static    OSErr    GetCommentID(short vRefNum,
  968.                              long dirID,
  969.                              StringPtr name,
  970.                              short *commentID)
  971. {
  972.     CInfoPBRec pb;
  973.     Str31 tempName;
  974.     OSErr error;
  975.  
  976.     /* Protection against File Sharing problem */
  977.     if ( (name == NULL) || (name[0] == 0) )
  978.     {
  979.         tempName[0] = 0;
  980.         pb.hFileInfo.ioNamePtr = tempName;
  981.         pb.hFileInfo.ioFDirIndex = -1;    /* use ioDirID */
  982.     }
  983.     else
  984.     {
  985.         pb.hFileInfo.ioNamePtr = name;
  986.         pb.hFileInfo.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
  987.     }
  988.     pb.hFileInfo.ioVRefNum = vRefNum;
  989.     pb.hFileInfo.ioDirID = dirID;
  990.     error = PBGetCatInfoSync(&pb);
  991.     *commentID = pb.hFileInfo.ioFlXFndrInfo.fdComment;
  992.     return ( error );
  993. }
  994.  
  995. /*****************************************************************************/
  996.  
  997. /*
  998. **    GetCommentFromDesktopFile
  999. **
  1000. **    Get a file or directory's Finder comment field (if any) from the
  1001. **    Desktop file's 'FCMT' resources.
  1002. */
  1003. static    OSErr    GetCommentFromDesktopFile(short vRefNum,
  1004.                                           long dirID,
  1005.                                           StringPtr name,
  1006.                                           Str255 comment)
  1007. {
  1008.     OSErr error;
  1009.     short commentID;
  1010.     short realVRefNum;
  1011.     Str255 desktopName;
  1012.     short savedResFile;
  1013.     short dfRefNum;
  1014.     StringHandle commentHandle;
  1015.     
  1016.     /* Get the comment ID number */
  1017.     error = GetCommentID(vRefNum, dirID, name, &commentID);
  1018.     if ( error == noErr )
  1019.     {
  1020.         if ( commentID != 0 )    /* commentID == 0 means there's no comment */
  1021.         {
  1022.             error = DetermineVRefNum(name, vRefNum, &realVRefNum);
  1023.             if ( error == noErr )
  1024.             {
  1025.                 error = GetDesktopFileName(realVRefNum, desktopName);
  1026.                 if ( error == noErr )
  1027.                 {
  1028.                     savedResFile = CurResFile();
  1029.                     /*
  1030.                     **    Open the 'Desktop' file in the root directory. (because
  1031.                     **    opening the resource file could preload unwanted resources,
  1032.                     **    bracket the call with SetResLoad(s))
  1033.                     */
  1034.                     SetResLoad(false);
  1035.                     dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
  1036.                     SetResLoad(true);
  1037.                     
  1038.                     if ( dfRefNum != -1)
  1039.                     {
  1040.                         /* Get the comment resource */
  1041.                         commentHandle = (StringHandle)Get1Resource(kFCMTResType,commentID);
  1042.                         if ( commentHandle != NULL )
  1043.                         {
  1044.                             if ( GetHandleSize((Handle)commentHandle) > 0 )
  1045.                                 BlockMoveData(*commentHandle, comment, *commentHandle[0] + 1);
  1046.                             else
  1047.                                 error = afpItemNotFound;    /* no comment available */
  1048.                         }
  1049.                         else
  1050.                             error = afpItemNotFound;    /* no comment available */
  1051.                         
  1052.                         /* restore the resource chain and close the Desktop file */
  1053.                         UseResFile(savedResFile);
  1054.                         CloseResFile(dfRefNum);
  1055.                     }
  1056.                     else
  1057.                         error = ResError();
  1058.                 }
  1059.             }
  1060.         }
  1061.         else
  1062.             error = afpItemNotFound;    /* no comment available */
  1063.     }
  1064.     
  1065.     return ( error );
  1066. }
  1067.  
  1068. /*****************************************************************************/
  1069.  
  1070. pascal    OSErr    DTGetComment(short vRefNum,
  1071.                              long dirID,
  1072.                              StringPtr name,
  1073.                              Str255 comment)
  1074. {
  1075.     DTPBRec pb;
  1076.     OSErr error;
  1077.     short dtRefNum;
  1078.     Boolean newDTDatabase;
  1079.  
  1080.     if (comment != NULL)
  1081.     {
  1082.         comment[0] = 0;    /* return nothing by default */
  1083.         
  1084.         /* attempt to open the desktop database */
  1085.         error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
  1086.         if ( error == noErr )
  1087.         {
  1088.             /* There was a desktop database and it's now open */
  1089.             
  1090.             if ( !newDTDatabase )
  1091.             {
  1092.                 pb.ioDTRefNum = dtRefNum;
  1093.                 pb.ioNamePtr = name;
  1094.                 pb.ioDirID = dirID;
  1095.                 pb.ioDTBuffer = (Ptr)&comment[1];
  1096.                 error = PBDTGetCommentSync(&pb);
  1097.                 if (error == noErr)
  1098.                     comment[0] = (unsigned char)pb.ioDTActCount;
  1099.             }
  1100.         }
  1101.         else
  1102.         {
  1103.             /* There is no desktop database - try the Desktop file */
  1104.             error = GetCommentFromDesktopFile(vRefNum, dirID, name, comment);
  1105.         }
  1106.     }
  1107.     else
  1108.         error = paramErr;
  1109.     
  1110.     return (error);
  1111. }
  1112.  
  1113. /*****************************************************************************/
  1114.  
  1115. pascal    OSErr    FSpDTGetComment(const FSSpec *spec,
  1116.                               Str255 comment)
  1117. {
  1118.     return (DTGetComment(spec->vRefNum, spec->parID, (StringPtr)spec->name, comment));
  1119. }
  1120.  
  1121. /*****************************************************************************/
  1122.  
  1123. pascal    OSErr    DTCopyComment(short srcVRefNum,
  1124.                               long srcDirID,
  1125.                               StringPtr srcName,
  1126.                               short dstVRefNum,
  1127.                               long dstDirID,
  1128.                               StringPtr dstName)
  1129. /* The destination volume must support the Desktop Manager for this to work */
  1130. {
  1131.     OSErr error;
  1132.     Str255 comment;
  1133.  
  1134.     error = DTGetComment(srcVRefNum, srcDirID, srcName, comment);
  1135.     if ( (error == noErr) && (comment[0] > 0) )
  1136.     {
  1137.         error = DTSetComment(dstVRefNum, dstDirID, dstName, comment);
  1138.     }
  1139.     return (error);
  1140. }
  1141.  
  1142. /*****************************************************************************/
  1143.  
  1144. pascal    OSErr    FSpDTCopyComment(const FSSpec *srcSpec,
  1145.                                const FSSpec *dstSpec)
  1146. /* The destination volume must support the Desktop Manager for this to work */
  1147. {
  1148.     return (DTCopyComment(srcSpec->vRefNum, srcSpec->parID, (StringPtr)srcSpec->name,
  1149.                         dstSpec->vRefNum, dstSpec->parID, (StringPtr)dstSpec->name));
  1150. }
  1151.  
  1152. /*****************************************************************************/
  1153.